#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <errno.h>

#include "logger.h"
#include "hook.h"
#include "httpserver.h"

using namespace std;
using namespace nmsp;

// 动态链接库路径
#define CONFIG_PATH "config.ini"
#define PLUGIN_INIT_FUNC "PluginInit" // 注意cpp编译后换名为 "_Z10PluginInitiPv",
// #define PLUGIN_INIT_FUNC "_Z10PluginInitiPv"

#define HTTPSERVER "httpserver"
#define HTTPSERVER_PORT 8585




// 函数指针
extern "C"
{
    typedef void (*PluginInit)(int sessionId, void *session);
}
//
std::list<std::string> loadConfig(const char *path)
{
    // 从配置文件中读取插件的名称, 插件库的路径在 bin 下, 生成的可执行文件也在 bin 下, 所以直接链接,
    std::list<std::string> lib_list;
    ifstream ifm(path);
    string tmp;

    if (ifm.is_open()) // 判断文件是否正常打开
    {
        while (getline(ifm, tmp)) // 每次读取一行到tmp中，默认以换行符作为分割条件
        {
            lib_list.emplace_back(tmp);
        }
    }
    else
    {
        cout << "Cant open the file" << endl;
    }

#if 0
    for (std::string &s : lib_list)
    {
        cout << s << endl;
        // shapeplugin
    }
    cout << *lib_list.begin() << endl;
#endif

    return std::move(lib_list);
}

void loadPlugin(const std::list<std::string> &plugins, int pluginSessionId, char const *argv[])
{
    void *handle = nullptr;
    char *error = nullptr;
    PluginInit call_func = nullptr;

    for (const std::string &name : plugins)
    {
        std::cout << "plugin is :" << name << std::endl;

        handle = dlopen(name.c_str(), RTLD_LAZY);
        if (!handle)
        {
            fprintf(stderr, "[%s:%s:%d] %s\n", __FILE__, __FUNCTION__, __LINE__, dlerror());
        }
        // 清除之前存在的错误
        dlerror();
        // 加载入口函数,
        *(void **)(&call_func) = dlsym(handle, PLUGIN_INIT_FUNC);
        if ((error = dlerror()) != NULL)
        {
            fprintf(stderr, "[%s:%s:%d] %s\n", __FILE__, __FUNCTION__, __LINE__, dlerror());
        }
        else
        {
            (*call_func)(pluginSessionId, nullptr);
        }
    }
}

INITIALIZE_EASYLOGGINGPP;

extern int *g_write_fd;
extern int *g_read_fd;

int main(int argc, char const *argv[])
{
    {
        // 只需要在 main() 开始时候初始化一次就够, 当然后续根据子集需要  defaultConf.set()  el::Loggers::reconfigureLogger,
        // defaultConf.setGlobally()   el::Loggers::reconfigureLogger(),
        el::Configurations defaultConf;
        defaultConf.set(el::Level::Info, el::ConfigurationType::Format, "%datetime %level %msg");
        defaultConf.setGlobally(el::ConfigurationType::Filename, "../log/log_%datetime{%Y%M%d_%H%m%s}.log");
        el::Loggers::reconfigureLogger("default", defaultConf);
    }

    MYLOG("cpp_plugin_http_demo start ...")
    int fd[2];
    g_write_fd = &fd[1];
    g_read_fd = &fd[0];
    if (-1 == pipe(fd)) // 这里就不处理 httplib_test 相关的了,
    {
        MYLOG("create pipe error!");
        exit(1);
    }

    // 开启线程池, 处理插件,
    std::list<std::string> pluginList = loadConfig(CONFIG_PATH);
    int pluginSessionId = 0;
    loadPlugin(pluginList, pluginSessionId, argv);

    // 主线程业务,
    Httpserver httpserver;
    if (0 == httpserver.Register())
        httpserver.Listen("0.0.0.0", HTTPSERVER_PORT);

    return 0;
}
